package com.beiding.natago2.component;

import com.beiding.dbrequest.common.Mapping;
import com.beiding.dbrequest.common.Message;
import com.beiding.dbrequest.common.Terminal;
import com.beiding.dbrequest.promise.Promise;
import com.beiding.dbrequest.server.Server;
import com.beiding.natago2.data.ByteData;
import com.beiding.natago2.utils.DataParser;
import com.beiding.natago2.utils.MyPrint;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.extern.java.Log;

import java.util.concurrent.ExecutorService;

/**
 * 服务端执行器
 */
@Log
@Mapping("/server")
public class ServerExecutor extends CsCommon {

    /**
     * 内部通道通信用的server
     */
    private Server server;


    /**
     * 绑定端口
     */
    private Integer serverPort;

    /**
     * 启动服务端
     * @return
     */
    public Promise start() {

        //注册控制器
        server.getDispatcher().addController(this);

        NioEventLoopGroup bossGroup = new NioEventLoopGroup();
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();
        ServerBootstrap serverBootstrap = new ServerBootstrap();
        serverBootstrap.group(bossGroup, workerGroup)
                .channel(NioServerSocketChannel.class)
                .option(ChannelOption.SO_BACKLOG, 1024)
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel ch) {
                        ch.pipeline()
                                .addLast(new ByteArrayDecoder())
                                .addLast(new ByteArrayEncoder())
                                .addLast(new H());

                    }
                });

        Promise promise = new Promise();

        //绑定端口
        ChannelFuture future = serverBootstrap.bind(serverPort);
        future.addListener(future1 -> {
            if (!future1.isSuccess()) {
                promise.doError(future1.cause());
            } else {
                promise.doOk("端口绑定成功 port:" + serverPort);
            }
        });
        return promise;
    }

    /**
     * 内部数据处理
     */
    public class H extends ChannelInboundHandlerAdapter {

        private ExecutorService executorService = ExecutorPool.getOne();

        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            executorService.submit(() -> {

                if (getDebugger()) {
                    byte[] data = (byte[]) msg;
                    printData("<<<===", data, "-------");
                }

                Long id = channelStore.getId(ctx);
                //判断通道是否处于激活状态,如果已经被销毁数据作废

                if (!channelStore.isActive(id)) {
                    log.info("通道已被关闭,数据忽略");
                    return;
                }
                ByteData byteData = new ByteData();
                byteData.setId(id);
                byteData.setData((byte[]) msg);
                try {
                    ChannelHandlerContext inner = channelStore.getInner(ctx);
                    Terminal.broadcastWithChannel(inner, Message.request("/client/onData", byteData));
                } catch (Exception e) {
                    log.info("发送目标数据失败 主动关闭通道" + id);
                    channelStore.close(ctx);
                    e.printStackTrace();
                }
            });
        }

        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            executorService.submit(() -> {
                channelStore.setId(ctx);
                channelStore.put(ctx);
                log.info("命令:客户端创建目标连接" + channelStore.getId(ctx));
                try {
                    ChannelHandlerContext one = server.getChannelByName("#");
                    if (one == null) {
                        log.warning("通道未建立");
                        channelStore.close(ctx);
                        return;
                    }
                    channelStore.bindInner(ctx, one);
                    Terminal.requestWithChannel(one, "/client/createTarget", channelStore.getId(ctx)).syncR();
                    log.info("命令:客户端创建目标连接-完成" + channelStore.getId(ctx));
                } catch (Exception e) {
                    log.info("命令:客户端创建目标连接-失败 主动关闭通道" + channelStore.getId(ctx));
                    channelStore.close(ctx);
                    e.printStackTrace();
                }
            });
        }

        @Override
        public void channelInactive(ChannelHandlerContext ctx) throws Exception {
            Long id = channelStore.getId(ctx);
            if (channelStore.isActive(id)) {
                executorService.submit(() -> {
                    channelStore.remove(id);
                    log.info("命令:客户端关闭目标连接" + id);

                    //获取内部绑定的通道,确保使用内部绑定的通道发送该请求
                    ChannelHandlerContext inner = channelStore.getInner(ctx);
                    Terminal.requestWithChannel(inner, "/client/close", id).syncR();
                    log.info("命令:客户端关闭目标连接-完成" + id);
                });
            }

        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            cause.printStackTrace();
        }
    }

    public void setServerPort(Integer serverPort) {
        this.serverPort = serverPort;
    }

    public void setServer(Server server) {
        this.server = server;
    }

}
